﻿/*******************************************************************************
 * @file nmea.h
 * @brief NMEA4.1 协议解析
 *******************************************************************************
*/

#ifndef __NMEA_H__
#define __NMEA_H__

#include <stdint.h>

#define NMEA_VERSION 41 // NMEA 协议版本号 4.1

#define NMEA_OK    1
#define NMEA_ERROR 0

/* GGA 数据结构体 */
typedef struct {
    char    time[11];       ///< UTC 时间，格式为 HHMMSS.SSS
    char    lat_dir;        ///< 纬度方向，'N' 表示北纬，'S' 表示南纬
    char    lon_dir;        ///< 经度方向，'E' 表示东经，'W' 表示西经
    uint8_t gps_state;      ///< GPS状态，0=未定位，1=非差分定位，2=差分定位，3=无效PPS，6=正在估算
    uint8_t num_satellites; ///< 正在使用的卫星数量
    float   latitude;       ///< 纬度，单位：度
    float   longitude;      ///< 经度，单位：度
    float   hdop;           ///< 水平精度因子，单位：米
    float   altitude;       ///< 海拔高度，单位：米
    float   geoid_sep;      ///< 大地水准面高度，单位：米
    float   age;            ///< 差分时间（从最近一次接收到差分信号开始的秒数，如果不是差分定位将为空）
    float   ref_station_id; ///< 差分参考站 ID
} NmeaGGA_t;

/* GLL 数据结构体 */
typedef struct {
    float latitude;  ///< 纬度，单位：度
    float longitude; ///< 经度，单位：度
    char  lat_dir;   ///< 纬度方向，N=北纬，S=表示南纬
    char  lon_dir;   ///< 经度方向，E=表示东经，W=表示西经
    char  status;    ///< 定位状态，A=表示有效定位，V=表示无效定位
    char  mode;      ///< 定位模式，A=自动定位，D=差分定位，E=估测定位，N=数据无效，M=未定位，但存在外部输入或历史保存的位置
    char  time[11];  ///< UTC 时间，格式为 HHMMSS.SSS
} NmeaGLL_t;

/* GSA 数据结构体 */
typedef struct
{
    char    mode;     ///< 定位模式，A=自动2D/3D，M=手动2D/3D
    uint8_t fix_type; ///< 定位类型，1=未定位，2=2D定位，3=3D定位
    uint8_t sys_id;   ///< 定位系统ID，1=GPS，2=GLONASS，4=北斗
    uint8_t prn[12];  ///< 正在使用的卫星 PRN 编号，范围 1 - 32
    float   pdop;     ///< 位置精度因子，单位：米
    float   hdop;     ///< 水平精度因子，单位：米
    float   vdop;     ///< 垂直精度因子，单位：米
} NmeaGSA_t;

/* GSV 数据结构体 */
typedef struct {
    uint8_t num_messages;           ///< 本次GSV语句的总数目 1-3
    uint8_t msg_number;             ///< 本条GSV语句是本次GSV语句的第几条（1-3）
    uint8_t num_satellites_in_view; ///< 当前可见卫星总数（00-12）
    uint8_t signal_id;               ///< GNSS信号ID（0代表全部信号）
    uint8_t satellite_prn[3];       ///< PRN码（伪随机噪声码）（01-32）
    uint8_t elevation[3];           ///< 卫星仰角，单位：度
    uint8_t azimuth[3];             ///< 卫星方位角，单位：度
    uint8_t snr[3];                 ///< 信噪比（00－99）dbHz
} NmeaGSV_t;

/* RMC 数据结构体 */
typedef struct {
    char  time[11];           ///< UTC 时间，格式为 HHMMSS.SSS
    char  status;             ///< 状态，A=定位，V=未定位
    float latitude;           ///< 纬度，单位：度
    char  lat_dir;            ///< 纬度方向，'N' 表示北纬，'S' 表示南纬
    float longitude;          ///< 经度，单位：度
    char  lon_dir;            ///< 经度方向，'E' 表示东经，'W' 表示西经
    float speed;              ///< 地面速度，单位：米/秒
    float course;             ///< 地面航向，单位：度
    char  date[7];            ///< 日期，格式为 DDMMYY
    float magnetic_variation; ///< 磁偏角，单位：度
    char  mag_var_dir;        ///< 磁偏角方向，'E' 表示东偏，'W' 表示西偏
    char  mode;               ///< 模式，A=自动，D=差分，E=估测，N=数据无效，M=未定位，但存在外部输入或历史保存的位置
    char nav_status;           ///< 导航状态，A=定位，V=未定位
} NmeaRMC_t;

/* VTG 数据结构体 */
typedef struct {
    char  mode;                ///< 模式，A=自动，D=差分，E=估测，N=数据无效，M=未定位，但存在外部输入或历史保存的位置
    float true_course;         ///< 真实航向，000-359，单位：度
    float magnetic_course;     ///< 磁航向，000-359，单位：度
    float speed_knots;         ///< 地面速度，单位：节
    float speed_kmh;           ///< 地面速度，单位：千米/小时
} NmeaVTG_t;

/* ZDA 数据结构体 */
typedef struct {
    char time[7]; ///< UTC 时间，格式为 HHMMSS
    int  day;     ///< 日期，范围 1 - 31
    int  month;   ///< 月份，范围 1 - 12
    int  year;    ///< 年份
    int  ltzh;    ///< 本时区小时
    int  ltzn;    ///< 本时区分钟
} NmeaZDA_t;

/**
 * @brief 解析 GGA 语句
 * @param nmea_sentence 输入的 NMEA GGA 语句字符串
 * @param data 用于存储解析结果的 NMEA_GGA_t 结构体指针
 * @return 解析到的语句字符串的结束位置指针
 */
int Nmea_ParseGGA(const char *nmea_sentence, NmeaGGA_t *data, char **end);

/**
 * @brief 解析 GLL 语句
 * @param nmea_sentence 输入的 NMEA GLL 语句字符串
 * @param data 用于存储解析结果的 NMEA_GLL_t 结构体指针
 * @param end 用于存储解析到的语句字符串的结束位置指针
 * @return 解析结果，NMEA_ERROR 表示解析失败，NMEA_OK 表示解析成功
 */
int Nmea_ParseGLL(const char *nmea_sentence, NmeaGLL_t *data, char **end);

/**
 * @brief 解析 GSA 语句
 * @param nmea_sentence 输入的 NMEA GST 语句字符串
 * @param data 用于存储解析结果的 NmeaGSA_t 结构体指针
 * @param end 下一个语句的起始位置
 * @return 解析结果，NMEA_ERROR 表示解析失败，NMEA_OK 表示解析成功
 */
int Nmea_ParseGSA(const char *nmea_sentence, NmeaGSA_t *data, char **end);

/**
 * @brief 解析 GSV 语句
 * @param nmea_sentence 输入的 NMEA GSV 语句字符串
 * @param data 用于存储解析结果的 NmeaGSV_t 结构体指针
 * @param end 下一个语句的起始位置
 * @return 解析结果，NMEA_ERROR 表示解析失败，NMEA_OK 表示解析成功
 */
int Nmea_ParseGSV(const char *nmea_sentence, NmeaGSV_t *data, char **end);

/**
 * @brief 解析 RMC 语句
 * @param nmea_sentence 输入的 NMEA RMC 语句字符串
 * @param data 用于存储解析结果的 NmeaRMC_t 结构体指针
 * @param end 下一个语句的起始位置
 * @return 解析结果，NMEA_ERROR 表示解析失败，NMEA_OK 表示解析成功
 */
int Nmea_ParseRMC(const char *nmea_sentence, NmeaRMC_t *data, char **end);

/**
 * @brief 解析 VTG 语句
 * @param nmea_sentence 输入的 NMEA VTG 语句字符串
 * @param data 用于存储解析结果的 NmeaVTG_t 结构体指针
 * @param end 下一个语句的起始位置
 * @return 解析结果，NMEA_ERROR 表示解析失败，NMEA_OK 表示解析成功
 */
int Nmea_ParseVTG(const char *nmea_sentence, NmeaVTG_t *data, char **end);

/**
 * @brief 解析 ZDA 语句
 * @param nmea_sentence 输入的 NMEA ZDA 语句字符串
 * @param data 用于存储解析结果的 NmeaZDA_t 结构体指针
 * @param end 下一个语句的起始位置
 * @return 解析结果，NMEA_ERROR 表示解析失败，NMEA_OK 表示解析成功
 */
int Nmea_ParseZDA(const char *nmea_sentence, NmeaZDA_t *data, char **end);

/**
 * @brief 获取下一个 NMEA 语句
 * @param nmea_sentence 输入的 NMEA 语句字符串
 * @return 下一个语句的起始位置指针，如果没有下一个语句则返回 NULL
 */
const char *Nmea_NextSentence(const char *nmea_sentence);

/**
 * @brief 查找指定的 NMEA 语句
 * @param nmea_sentence 输入的 NMEA 语句字符串
 * @param header 要查找的 NMEA 语句头 e.g. "GGA", "GLL" 等
 * @return 找到的语句的起始位置指针，如果没有找到则返回 NULL
 */
const char *Nmea_FindSentence(const char *nmea_sentence, const char *header);

#endif // __NMEA_H__
